package com.zhouke.certificate.controller;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zhouke.certificate.common.Result;
import com.zhouke.certificate.entity.Files;
import com.zhouke.certificate.mapper.FileMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;

/**
 * 文件上传接口
 */
@RestController
@RequestMapping("/file")
public class FileController {

    @Value("${files.upload.path}")
    private String fileUploadPath;  //获取配置文件中定义的路径
    @Value("${server.ip}")
    private String serverIp;
    @Resource
    private FileMapper fileMapper;

    @Resource
    private StringRedisTemplate stringRedisTemplate;
    public static final String FILES_KEY="FILES_ALL";

    /**
     * 文件上传接口
     * @param file 前端传递过来的文件
     * @return
     * @throws IOException
     */
    @PostMapping("/upload")
    public String upload(@RequestParam MultipartFile file) throws IOException { //通过 ? 加在链接后面
        String originalFilename=file.getOriginalFilename();
        String type= FileUtil.extName(originalFilename);
        long size = file.getSize();

        // 判断 目录 是否存在
        File uploadParentFile=new File(fileUploadPath);
        if(!uploadParentFile.exists()){
            uploadParentFile.mkdirs(); // 创建由此File表示的文件夹,包括任何必须但是又不存在的父目录.
        }

        //先将文件上传到磁盘
        String uuid = IdUtil.fastSimpleUUID();//生成一个唯一的文件名
        //创建文件
        File uploadFile = new File(fileUploadPath + uuid+ StrUtil.DOT + type);
        file.transferTo(uploadFile);//将上传的文件存储到创建的文件

        //获取文件的md5
        String md5= SecureUtil.md5(uploadFile);
        // 查看文件是否重复
        Files files = getFileByMd5(md5);
        String url;

        if(files!=null){//如果文件已存在
            uploadFile.delete();
            url=files.getUrl();//文件指向已存在的文件
        }else{
            url="http://"+serverIp+":9090/file/"+uuid+ StrUtil.DOT + type;
        }

        // 存储到数据库
        Files saveFile = new Files();
        saveFile.setName(originalFilename);
        saveFile.setType(type);
        saveFile.setSize(size/1024); //KB
        saveFile.setUrl(url);
        saveFile.setMd5(md5);
        fileMapper.insert(saveFile);
        //删除缓存
        stringRedisTemplate.delete(FILES_KEY);

        return url;
    }

    /**
     * 文件下载接口
     * @param fileUUID
     * @param response
     * @throws IOException
     */
    @GetMapping("/{fileUUID}")
    public void download(@PathVariable String fileUUID, HttpServletResponse response) throws IOException{
        //根据文件标识获取文件
        File uploadFile = new File(fileUploadPath + fileUUID);
        //设置输出流格式
        ServletOutputStream os=response.getOutputStream();
        response.addHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileUUID,"UTF-8"));
        response.setContentType("application/octet=stream");

        //读取文件的字符流
        os.write(FileUtil.readBytes(uploadFile));
        os.flush();
        os.close();
    }

    /**
     * 通过文件的md5 查询文件
     * @param md5
     * @return
     */
    private Files getFileByMd5(String md5){
        QueryWrapper<Files> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("md5",md5);
        List<Files> filesList = fileMapper.selectList(queryWrapper);
        return  filesList.size()==0?null:filesList.get(0);
    }
    //删除
    @DeleteMapping("/{id}")
//    @CacheEvict(value = "files",key = "'allFile'") //清除一条缓存  第一次请求会请求数据库
    public Result delete(@PathVariable Integer id) {
        Files files = fileMapper.selectById(id);
        files.setIsDelete(true);
        fileMapper.updateById(files);
        stringRedisTemplate.delete(FILES_KEY);
        return Result.success(); // table.entityPath= user
    }

    //批量删除
    @PostMapping("/del/batch")
    public Result deleteBatch(@RequestBody List<Integer> ids){
        //select * from sys_file where id in (ids)
        QueryWrapper<Files> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("id",ids);
        List<Files> files = fileMapper.selectList(queryWrapper);
        for(Files file:files){
            file.setIsDelete(true);
            fileMapper.updateById(file);
        }
        return Result.success();
    }

    //更新
    @PostMapping("/update")
//    @CachePut(value = "files",key = "'allFile'")//执行此方法后更新缓存 第一次刷新不会重新请求数据库
    public Result update(@RequestBody Files files) {
        int i = fileMapper.updateById(files);
        stringRedisTemplate.delete(FILES_KEY);
        return Result.success(fileMapper.selectList(null));//更新完
    }


    @GetMapping("/getAll")
//    @Cacheable(value = "files",key = "targetClass+methodName")//key="FileController+getAll" 不用经常访问数据库
//    @Cacheable(value = "files",key = "'allFile'")
    public Result getAll(){
        //使用Redis
        //从缓存获取数据
        String jsonStr=stringRedisTemplate.opsForValue().get(FILES_KEY);
        List<Files> files;
        if(StrUtil.isBlank(jsonStr)){//没有数据
            files = fileMapper.selectList(null);
            //再去缓存
            stringRedisTemplate.opsForValue().set(FILES_KEY,JSONUtil.toJsonStr(files));
        }else{//有数据
            files=JSONUtil.toBean(jsonStr, new TypeReference<List<Files>>() {
            }, true);
        }

        return Result.success(files);
    }

    //根据id查询
    @GetMapping("/detail/{id}")
    public Result findOne(@PathVariable Integer id) { // 返回 Certificates
        return Result.success(fileMapper.selectById(id));
    }

    //分页查询
    @GetMapping("/page")
    public Result findPage(@RequestParam Integer pageNum,
                           @RequestParam Integer pageSize,
                           @RequestParam(defaultValue = "") String name) {

        QueryWrapper<Files> queryWrapper=new QueryWrapper<>();

        queryWrapper.eq("is_delete",false);
        if(!"".equals(name)){
            queryWrapper.like("name",name);
        }
        queryWrapper.orderByDesc("id");

        return Result.success(fileMapper.selectPage(new Page<>(pageNum, pageSize),queryWrapper));
    }

}
